<?php
/**
 * @author spenceryg
 * @date 2022/2/17
 * @time 9:04 下午
 * @focus love & life
 */


namespace app\common\traits\model;


use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Db;
use think\Model;

trait ModelTreeTrait
{
    /**
     * sons获取器
     * @param $value
     * @param $data
     * @return string|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getSonsAttr($value, $data): ?string
    {
        $arr = Db::table($this->table)->where('delete_time', null)->select()->toArray();
        if ($arr) {
            $sons = getSons($arr, $data['id']);
            if ($sons) {
                $ids = array_column($sons, 'id');
                return ',' . implode(',', $ids) . ',';
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * descendants获取器
     * @param $value
     * @param $data
     * @return string|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getDescendantsAttr($value, $data): ?string
    {
        $arr = Db::table($this->table)->where('delete_time', null)->select()->toArray();
        if ($arr) {
            $sons = getSubs($arr, $data['id']);
            if ($sons) {
                $ids = array_column($sons, 'id');
                return ',' . implode(',', $ids) . ',';
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * forefathers获取器
     * @param $value
     * @param $data
     * @return string|null
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function getForefathersAttr($value, $data): ?string
    {
        $arr = Db::table($this->table)->where('delete_time', null)->select()->toArray();
        if ($arr) {
            $parents = getParents($arr, $data['id']);
            if ($parents) {
                $ids = array_column($parents, 'id');
                return ',' . implode(',', $ids) . ',';
            } else {
                return null;
            }
        } else {
            return null;
        }
    }



    /**
     * 获取level层级
     * @param Model $model
     * @return int|mixed
     */
    public static function getLevel(Model $model)
    {
        return $model->getData('pid') ? self::where('id', $model->getData('pid'))->value('level') + 1 : 1;
    }


    /**
     * 获取树状排序
     * @param Model $model
     * @param int $tree_level
     * @return float|int|mixed
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function getTreeSort(Model $model, int $tree_level)
    {
        if ($model->getData('pid')) {
            $pid_data = self::find($model->getData('pid'));
            $max = $pid_data['sort'] + pow(100, ($tree_level - $pid_data['level']));
            $max_sort = self::where('sort', '<', $max)->order('sort desc')->value('sort');
            $sort = ($max_sort / pow(100, $tree_level - $pid_data['level'] - 1) + 1) * pow(100, ($tree_level - $pid_data['level'] - 1));
        } else {
            $max = pow(100, $tree_level) * 2;
            $max_sort = self::where('sort', '<', $max)->order('sort desc')->value('sort');
            if (!$max_sort) {
                $sort = pow(100, $tree_level);
            } else {
                $sort = $max_sort + pow(100, ($tree_level - 1));
            }

        }
        return $sort;
    }


    public static function getTreeTableList(int $tree_level = 3)
    {
        $data = self::select();
        $res = [];
        foreach ($data as $item) {
            $res[$item['id']] = $item;
        }
        foreach ($data as $item) {
            $this_sort = 0;
            $pid_arr = $item['Forefathers']? explode(',', trim($item['Forefathers'], ',')):[];
            $pid_arr = array_reverse($pid_arr);
            foreach ($pid_arr as $id) {
                $this_sort += pow(100, ($tree_level - $res[$id]['level'])) * $res[$id]['sort'];
            }
            $this_sort += pow(100, ($tree_level - $item['level'])) * $item['sort'];
            $item['real_sort'] = $this_sort;
        }

        return $data->order('real_sort', 'asc');
    }


    /**
     * getSort
     * @param Model $model
     * @return int
     * @throws DbException
     */
    public static function getSort(Model $model)
    {
        $pid = $model->getData('pid');
        return $model->where('pid', $pid)->count()  * 10;
    }



    /**
     * 树状结构删除
     * @param $id
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public static function treeDelete($id)
    {
        $model = self::find($id);
        $descendants = $model->descendants;
        if($descendants){
            $descendants_arr = explode(',', trim($descendants, ','));
            foreach($descendants_arr as $id){
                self::destroy($id);
            }
        }
        $model->delete();
    }
}
